<link rel="import" href="../polymer/polymer.html">

<dom-module id="tf-graph-icon">
  <template>
    <template is="dom-if" if="[[_isType(node, type, 'OP')]]">
      <template is="dom-if" if="[[_isConst(node, const)]]">
        <svg height$="[[height]]"
            preserveAspectRatio="xMinYMid meet" viewBox="0 0 10 10">
          <circle cx="5" cy="5" r="3"
              fill$="[[_getFill(_computedFill, 'OP')]]"
              stroke$="[[_getStroke(_computedFill, 'OP')]]" />
        </svg>
      </template>
      <template is="dom-if" if="[[_isSummary(node, summary)]]">
        <svg width$="[[height]]" height$="[[height]]" viewBox="0 0 12 12">
          <use x="0" y="0" xlink:href="#summary-icon" />
        </svg>
      </template>
      <template is="dom-if" if="[[_isRegularOp(node, const, summary)]]">
        <svg height$="[[height]]"
            preserveAspectRatio="xMinYMid meet" viewBox="0 0 16 8">
          <use xmlns:xlink="http://www.w3.org/1999/xlink"
              xlink:href="#op-node-stamp"
              fill$="[[_getFill(_computedFill, 'OP')]]"
              stroke$="[[_getStroke(_computedFill, 'OP')]]"
              x="8" y="4" />
        </svg>
      </template>
    </template>
    <template is="dom-if" if="[[_isType(node, type, 'META')]]">
      <svg height$="[[height]]"
            preserveAspectRatio="xMinYMid meet" viewBox="0 0 37 16">
        <rect x="1" y="1"
            fill$="[[_getFill(_computedFill, 'META')]]"
            stroke$="[[_getStroke(_computedFill, 'META')]]"
            stroke-width="2px"
            height="14" width="35"
            rx="5" ry="5" />
      </svg>
    </template>
    <template is="dom-if" if="[[_isType(node, type, 'SERIES')]]">
      <template is="dom-if" if="[[_isVertical(node, vertical)]]">
        <svg height$="[[height]]"
            preserveAspectRatio="xMinYMid meet" viewBox="0 0 16 15">
          <use xmlns:xlink="http://www.w3.org/1999/xlink"
              xlink:href="#op-series-vertical-stamp"
              fill$="[[_getFill(_computedFill, 'SERIES')]]"
              stroke$="[[_getStroke(_computedFill, 'SERIES')]]"
              x="0" y="2" />
        </svg>
      </template>
      <template is="dom-if" if="[[!_isVertical(node, vertical)]]">
        <svg height$="[[height]]"
            preserveAspectRatio="xMinYMid meet" viewBox="0 0 24 10">
          <use xmlns:xlink="http://www.w3.org/1999/xlink"
              xlink:href="#op-series-horizontal-stamp"
              fill$="[[_getFill(_computedFill, 'SERIES')]]"
              stroke$="[[_getStroke(_computedFill, 'SERIES')]]"
              x="0" y="1" />
        </svg>
      </template>
    </template>
  </template>

  <script>
    (function() {
      Polymer({
        is: 'tf-graph-icon',

        properties: {
          /**
           * Node to represent with an icon. Optional, but if specified, its
           * properties override those defined in the type, vertical, const and
           * summary properties.
           * @type {tf.graph.Node}
           */
          node: {
            type: Object,
            value: null
          },

          /**
           * Render node information associated with this node. Optional. If
           * specified, this is only used when computing the fill of the icon
           * element.
           * @type {tf.graph.render.RenderNodeInfo}
           */
          renderInfo: {
            type: Object,
            value: null
          },

          /**
           * String indicating the type of coloring to use for this node, used
           * only for determining the fill.
           */
          colorBy: {
            type: Object,
            value: "structural"
          },

          /**
           * Function used by structural coloring algorithm to determine which
           * color to use based on the template ID of the node. Optional.
           */
          templateIndex: {
            type: Function,
            value: null
          },

          /** Type of node to draw (ignored if node is set). */
          type: {
            type: String,
            value: null
          },

          /** Direction for series (ignored for other types). */
          vertical: {
            type: Boolean,
            value: false
          },

          /** Whether the op is Const (ignored for non-ops). */
          const: {
            type: Boolean,
            value: false
          },

          /** Whether the op is a Summary (ignored for non-ops). */
          summary: {
            type: Boolean,
            value: false
          },

          /**
           * Fill for the icon, optional. If fill is specified and node is not
           * specified, then this value will override the default for the
           * element. However, if node is specified, this value will be ignored.
           */
          fill: {
            type: String,
            value: null
          },

          /** Height of the SVG element in pixels, used for scaling. */
          height: {
            type: Number,
            value: 20
          },

          /** The computed fill for the node. **/
          _computedFill: {
            type: String,
            computed:
              "_getComputedFill(node, renderInfo, colorBy, templateIndex, fill)"
          }

        },

        /**
         * Get the computed fill value for the element.
         */
        _getComputedFill: function(inputNode, inputRenderInfo, inputColorBy,
            inputTemplateIndex, inputFill) {
          if (inputNode && inputRenderInfo &&
              inputColorBy && inputTemplateIndex) {
            var ns = tf.graph.scene.node;
            var colorBy = ns.ColorBy[inputColorBy.toUpperCase()];
            return ns.getFillForNode(inputTemplateIndex, colorBy,
                inputRenderInfo, false);
          }
          return inputFill;
        },

        /**
         * Get the fill value for the element, or if that's not possible, return
         * the default fill value for the node type.
         */
        _getFill: function(inputComputedFill, inputNodeType) {
          return inputComputedFill || ({
            OP: tf.graph.render.OpNodeColors.DEFAULT_FILL,
            META: tf.graph.render.MetanodeColors.DEFAULT_FILL,
            SERIES: tf.graph.render.SeriesNodeColors.DEFAULT_FILL
          })[inputNodeType];
        },

        /**
         * Get the stroke value for the element, or if that's not possible,
         * return the default stroke value for the node type.
         */
        _getStroke: function(inputComputedFill, inputNodeType) {
          return inputComputedFill ?
            tf.graph.scene.node.getStrokeForFill(inputComputedFill) :
            ({
              OP: tf.graph.render.OpNodeColors.DEFAULT_STROKE,
              META: tf.graph.render.MetanodeColors.DEFAULT_STROKE,
              SERIES: tf.graph.render.SeriesNodeColors.DEFAULT_STROKE
            })[inputNodeType];
        },

        /**
         * Test whether the specified node's type, or the literal type string,
         * match a particular other type.
         */
        _isType: function(inputNode, inputType, targetType) {
          if (inputNode) {
            return tf.graph.NodeType[inputNode.type] === targetType;
          }
          return inputType === targetType;
        },

        /**
         * Test whether the specified node should be represented as a vertical
         * series. Defaults to the value of the vertical property if node is
         * not specified.
         */
        _isVertical: function(inputNode, inputVertical) {
          if (inputNode) {
            return inputNode.hasNonControlEdges;
          }
          return !!inputVertical;
        },

        /**
         * Test whether the specified node is a constant. Defaults to the value
         * of the const property if node is not specified.
         */
        _isConst: function(inputNode, inputConst) {
          if (inputNode) {
            return inputNode.op === 'Const';
          }
          return !!inputConst;
        },

        /**
         * Test whether the specified node is a summary. Defaults to the value
         * of the summary property if node is not specified.
         */
        _isSummary: function(inputNode, inputSummary) {
          if (inputNode) {
            return this._isType(inputNode, null, 'OP') &&
                inputNode.op.substr(-7) === 'Summary';
          }
          return !!inputSummary;
        },

        /**
         * Test whether the op node is a regular non-summary non-const node.
         */
        _isRegularOp: function(inputNode, inputConst, inputSummary) {
          return !this._isConst(inputNode, inputConst) &&
              !this._isSummary(inputNode, inputSummary);
        }
      });
    })();
  </script>
</dom-module>
